home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************************
-
- NamerUTIL.c - The NamerUTIL, a UTIL that allows the LaserWriter Font Utility to rename
- PostScript printers.
-
- Written by Bryan K. Ressler (Beaker), 10/8/91
-
- *****************************************************************************************/
-
- /* --- Includes ----------------------------------------------------------------------- */
- #include <Types.h> /* Macintosh includes */
- #include <Memory.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <Dialogs.h>
- #include <Printing.h>
- #include <ToolUtils.h>
- #include <Errors.h>
-
- #include "UTIL.h" /* Standard UTIL constants and structs */
- #include "NamerResIDs.h" /* "Relative" resource IDs */
-
- /* --- Defines ------------------------------------------------------------------------ */
- #define kMinVersion 1 /* The minimum format version we'll run */
-
- #define kPSErrStr 1 /* Strings in the 'STR#' kNamerStrs */
- #define kExitVerStr 2
- #define kRenameStartStr 3
- #define kRenameEndStr 4
-
- #define kNDDummy 0 /* Item numbers in the Namer dialog box */
- #define kNDRename 1
- #define kNDCancel 2
- #define kNDNewName 6
- #define kNDBoldOutline 7
-
- #define kReturnKey 0x0d /* Key and character code constants */
- #define kEnterKey 0x03
- #define kBackspaceKey 0x08
- #define kAtChar '@'
- #define kColonChar ':'
- #define kLowASCII 0x7f
-
- #define kMaxNameLength 30 /* Maximum printer name length */
- #define kNameBufLen 40 /* Size of buffers for holding printer names */
- #define kCompStrLen 80 /* Size of buffers for parse strings */
-
- /* --- Prototypes --------------------------------------------------------------------- */
- pascal Boolean Utility_Open(LWFUParmBlk *pb);
- pascal Boolean Utility_Delta(LWFUParmBlk *pb);
- pascal unsigned long Utility_Prime(LWFUParmBlk *pb);
- pascal void Utility_Close(LWFUParmBlk *pb);
- pascal short ExitBufferRtn(short length, LWFUParmBlk *pb);
- pascal Boolean NamerFilter(DialogPtr TheDialog, EventRecord *TheEvent,
- short *ItemHit);
- short RenamePrinter(LWFUParmBlk *pb);
-
- /* ------------------------------------------------------------------------------------ */
- pascal Boolean Utility_Open(LWFUParmBlk *pb)
- {
- /*
- Normally Utility_Open does two things -- it tells the LaserWriter Font Utility
- whether it should install this UTIL or not and, if needed, it allocates any
- memory the UTIL might need.
-
- For our UTIL, we don't need any memory, so all we do is check to make sure that
- the parmeter block is recent enough for us, and if so, return TRUE, which means
- "install me!"
- */
- return(pb->version >= kMinVersion);
- }
-
- /* ------------------------------------------------------------------------------------ */
- pascal Boolean Utility_Delta(LWFUParmBlk *pb)
- {
- #pragma unused(pb)
-
- /*
- Utility_Delta is called every time the printer has been changed in the Chooser.
- If your UTIL is device- or characteristic-specific, it can use the Utility_Delta
- routine to decide whether it should be dimmed or not. To help your UTIL decide,
- the parameter block has lots of useful printer configuration information in its
- printerInfo structure. If that's not enough, you can call DoWrite from your
- Utility_Delta routine to send some PostScript code down that determines the
- printer is up to snuff, then return TRUE/FALSE depending upon what comes back
- from the printer. Since we can rename any PostScript device (assuming it's
- exitserver password is 0), we just return TRUE here, so this UTIL will always
- be available (never dimmed).
- */
- return(true);
- }
-
- /* ------------------------------------------------------------------------------------ */
- pascal unsigned long Utility_Prime(LWFUParmBlk *pb)
- {
- /*
- Utility_Prime is the routine that gets called when the user chooses your UTIL
- from the Utilities menu. It should carry out the main function of your UTIL.
- For us, we call RenamePrinter to pose the dialog and rename the printer. If
- RenamePrinter returns TRUE, meaning it successfully renamed the printer, we
- use the following return codes:
-
- Return code Description
- ----------------- --------------------------------------------------------
- urCheckPrinter Tells the LWFU that the printer may have changed
- urCheckFeatures Tells the LWFU to re-query the printer for features
- urEraseLists Tells the LWFU to forget any font lists it has around
-
- Basically, we're telling it to forget everything and start over, since the
- printer has been renamed. urCheckPrinter and urCheckFeatures have the side-
- effect of causing the Utility_Delta routines to be called for all the UTILs.
-
- If the user cancelled the Rename dialog or the printer couldn't be renamed
- because of some PostScript error, RenamePrinter returns FALSE, in which case
- we just return urNoAction, like nothing ever happened (RenamePrinter, however,
- already put up an alert describing the problem to the user).
- */
- if (RenamePrinter(pb))
- return(urCheckPrinter | urCheckFeatures | urEraseLists);
- else return(urNoAction);
- }
-
- /* ------------------------------------------------------------------------------------ */
- pascal void Utility_Close(LWFUParmBlk *pb)
- {
- #pragma unused(pb)
- /*
- Normally, Utility_Close releases storage the UTIL might have allocated and
- stuffed into pr->uStorage. Since we don't have any "global" storage, we
- don't do anything in this routine.
- */
- }
-
- /* ------------------------------------------------------------------------------------ */
- pascal short ExitBufferRtn(short length, LWFUParmBlk *pb)
- {
- Handle dataHandle; /* Our "handlized" copy of the printer response */
- short status; /* The return code */
- char psErrorText[kCompStrLen]; /* Buffer for our "fail" test */
- char exitText[kCompStrLen]; /* Buffer for our "success" test */
-
- /*
- ExitBufferRtn's job is to understand the text feedback that comes back from
- the printer. Really all that means is comparing it with known strings.
- So here we retrieve the text we'll use to detect an error (i.e. kPSErrStr),
- and the text we'll use to verify that we successfully exited the server
- loop (i.e. kExitVerStr).
- */
- GetIndString(psErrorText, pb->resSpace + kNamerStrs, kPSErrStr);
- GetIndString(exitText, pb->resSpace + kNamerStrs, kExitVerStr);
-
- /*
- Now, in order to make use of everyone's favorite routine, Munger, we
- "handlize" the data that came back from the printer.
- */
- PtrToHand(pb->callBacks->PAPReadBuffer, &dataHandle, length);
-
- /*
- Now, we search dataHandle looking for either psErrorText or exitText,
- and set the appropriate status return code.
- */
- if (Munger(dataHandle, 0, psErrorText + 1, *psErrorText, nil, 0) >= 0)
- status = printerError;
- else if (Munger(dataHandle, 0, exitText + 1, *exitText, nil, 0) >= 0)
- status = noErr;
- else status = printerError;
-
- /* Finally, dispose our copy of the printer feedback and return status. */
- DisposHandle(dataHandle);
- return(status);
- }
-
- /* ------------------------------------------------------------------------------------ */
- pascal Boolean NamerFilter(DialogPtr TheDialog, EventRecord *TheEvent, short *ItemHit)
- {
- unsigned char theKey; /* The ASCII code from the event record */
- short retVal = false; /* The return value */
- char newName[kNameBufLen]; /* The copy of the new name */
- LWFUParmBlk *pb; /* Pointer to our parameter block */
-
- /* Retrieve a pointer to our parameter block */
- pb = (LWFUParmBlk *)((WindowPeek)TheDialog)->refCon;
-
- /* Trap keyDown and autoKey events */
- if (TheEvent->what == keyDown || TheEvent->what == autoKey) {
-
- /* Grab the ASCII character code from the event record */
- theKey = TheEvent->message & charCodeMask;
-
- if (theKey == kReturnKey || theKey == kEnterKey) {
- /* Return or Enter? Hit the default button */
- retVal = true;
- *ItemHit = kNDRename;
- } else if (theKey == kAtChar || theKey == kColonChar || theKey > kLowASCII) {
- /* "@", ":", or a high ASCII character? Eat event and beep */
- SysBeep(5);
- retVal = true;
- *ItemHit = kNDDummy;
- } else if (theKey != kBackspaceKey) {
- /* Key other than backspace? Check length, decide whether to take the key */
- pb->callBacks->GetPText(TheDialog, kNDNewName, newName);
- if (*newName >= kMaxNameLength) {
- SysBeep(5);
- retVal = true;
- *ItemHit = kNDDummy;
- } else retVal = false;
- }
- } else retVal = false;
- return(retVal);
- }
-
- /* ------------------------------------------------------------------------------------ */
- short RenamePrinter(LWFUParmBlk *pb)
- {
- DialogPtr nameDlg; /* Pointer to the Rename dialog */
- short itemHit; /* Item hit from ModalDialog */
- char psBuffer[150]; /* Buffer for out PostScript code */
- char newName[kNameBufLen]; /* New printer name from editText item */
- char blankStr[1]; /* Blank string used everywhere */
- short status; /* The status from ExitBufferRtn */
- Point where; /* Used for positioning the dialog */
- LWFUCallBackInfo *cb; /* Cached pointer to the callback array */
- Boolean doneFlag = false; /* Flags to dismiss the dialog */
- Boolean renameFlag = false; /* Flags whether to do rename operation */
- Boolean retVal = false; /* TRUE or FALSE on success */
-
- /*
- First, clear blankStr (used all over the place), and get the dialog from
- the resource file. Also, set up cb, a cached version of the callback structure
- pointer, so can elminate half the pointer math for each callback.
- */
- *blankStr = 0;
- nameDlg = GetNewDialog(pb->resSpace + kNamerDlg, nil, (WindowPtr)-1);
- cb = pb->callBacks;
-
- /*
- Now, using a handy callback, center our "Rename printer" dialog box on the
- main screen. CenterDialog sets a point which we should use for the top, left
- of or dialog. So, we MoveWindow the (still hidden) dialog to where.h, where.v.
- */
- cb->CenterDialog(nameDlg, &where);
- MoveWindow(nameDlg, where.h, where.v, true);
-
- /*
- To be friendly, we put the current printer name in the dialog so the user can
- see it. No need to send PostScript to determine the printer name -- it's
- already in pb's printerInfo record. So, we just ParamText it in there.
- */
- ParamText(pb->printerInfo->currentPrinterName, blankStr, blankStr, blankStr);
-
- /*
- Why be fascist? We set the initial text of the new printer name to be blank.
- Also, we install a user item to do the "bold outline" around the default button.
- Handily, there's a callback to install a userItem procedure, AND there's a
- callback userItem that does the bold outline item! Wow! Cool!
- */
- cb->SetPText(nameDlg, kNDNewName, blankStr);
- cb->UserItem(nameDlg, kNDBoldOutline, cb->BoldOutlineItem);
-
- /*
- Now that everything's set up, let's put up the dialog. In order to allow our
- dialog filter (NamerFilter) to have access to our LWFUParmBlk, we install a
- pointer to the block into the dialog window's refCon field, then ShowWindow the
- dialog.
- */
- (LWFUParmBlk *)((DialogPeek)nameDlg)->window.refCon = pb;
- ShowWindow((WindowPtr)nameDlg);
-
- /*
- Now hit ModalDialog until the guy does something. NamerFilter will ensure
- the guy doesn't enter any illegal characters (like @ and :, which aren't
- allowed in PostScript printer names) and will also make sure the length of
- the name is okay. If the guy dismisses the dialog with the kNDRename button,
- then we set the renameFlag to TRUE, telling us we should rename the printer.
- */
- do {
- ModalDialog(NamerFilter, &itemHit);
- switch(itemHit) {
- case kNDRename: /* Rename */
- renameFlag = doneFlag = true;
- break;
- case kNDCancel: /* Cancel */
- doneFlag = true;
- break;
- }
- } while (!doneFlag);
-
- /*
- First, hide the dialog window. If the guy hit the "Rename" button, then
- we need to retrieve the new name and send some PostScript code to rename
- the printer.
- */
- HideWindow((WindowPtr)nameDlg);
- if (renameFlag) {
-
- /*
- The first part of renaming the printer is to construct a suitable
- PostScript program. The program in PostScript to rename the printer
- is basically this:
-
- serverdict begin
- 0 exitserver
- statusdict begin
- (NewPrinterName) setprintername
- end
-
- where NewPrinterName is the actual text of the new printer name. So
- we've stored the first part (up thru the open parenthese) as one string
- in our string list, and the last part (from the closed parenthese thru
- the "end") in another string. So to construct the program we just take
- the string kRenameStartStr, append the name from the dialog, then append
- kRenameEndStr. Do we need to write code to concatenate Pascal strings?
- No way, dude! Callbacks! (GetAndAppend is like GetIndString except that
- it appends the string to the input instead of replacing the input).
- */
- GetIndString(psBuffer, pb->resSpace + kNamerStrs, kRenameStartStr);
- cb->GetPText(nameDlg, kNDNewName, newName);
- cb->Pstrcat(psBuffer, newName);
- cb->GetAndAppend(psBuffer, pb->resSpace + kNamerStrs, kRenameEndStr);
-
- /*
- Now we need to send our nifty little rename program to the printer. The
- first step is opening the printer with OpenPrinter(). If successful, we
- send the program with DoWrite, also passing a pointer to our "feedback
- analyzer," ExitBufferRtn. It'll parse the output from the printer and
- return a status code. ExitBufferRtn's status code will in turn be returned
- as the result of DoWrite, so we can see whether the rename operation was
- successful. Even if the DoWrite returned some ugly status, we still need
- to close the printer with ClosePrinter.
- */
- if ((status = cb->OpenPrinter()) == noErr) {
- status = cb->DoWrite(psBuffer + 1, (short)*psBuffer, sendEOF, pb, ExitBufferRtn);
- cb->ClosePrinter();
- }
-
- /*
- If status was noErr (in other words, the rename operation was successful),
- then we put up an alert telling the user he needs to choose the newly-
- renamed printer in the Chooser. The alert kindly reminds him what he
- renamed the printer to.
-
- If status was some error, we put up an alert that says an error occured.
- */
- cb->UseCursor(0);
- if (status == noErr) {
- retVal = true;
- ParamText(newName, blankStr, blankStr, blankStr);
- cb->PositionAlert(pb->resSpace + kVerifyAlrt);
- CautionAlert(pb->resSpace + kVerifyAlrt, nil);
- } else {
- retVal = false;
- cb->PositionAlert(pb->resSpace + kFailAlrt);
- StopAlert(pb->resSpace + kFailAlrt, nil);
- }
- }
-
- /*
- Now we dispose or (hidden) dialog, and return TRUE/FALSE on the success of the
- operation.
- */
- DisposDialog(nameDlg);
- return(retVal);
- }
-